<?php
declare(strict_types=1);
/**
 * MineAdmin is committed to providing solutions for quickly building web applications
 * Please view the LICENSE file that was distributed with this source code,
 * For the full copyright and license information.
 * Thank you very much for using MineAdmin.
 *
 * @Author X.Mo<root@imoi.cn>
 * @Link   https://gitee.com/xmo/MineAdmin
 */

namespace App\Box\Mapper;

use App\Box\Model\BoxProduct;
use App\Lib\AdminEnum;
use Hyperf\Database\Model\Builder;
use Hyperf\DbConnection\Db;
use Mine\Abstracts\AbstractMapper;
use Whoops\Exception\ErrorException;

/**
 * 盒子关联产品Mapper类
 */
class BoxProductMapper extends AbstractMapper
{
    /**
     * @var BoxProduct
     */
    public $model;
    const UPDATE_BOX_PRICE_YES = 1; //更新
    const UPDATE_BOX_PRICE_NO = 2;  //不更新

    public function assignModel()
    {
        $this->model = BoxProduct::class;
    }

    /**
     * 搜索处理器
     * @param Builder $query
     * @param array $params
     * @return Builder
     */
    public function handleSearch(Builder $query, array $params): Builder
    {

        // ID
        if (isset($params['id']) && filled($params['id'])) {
            $query->where('id', '=', $params['id']);
        }

        // 盒子id
        if (isset($params['box_id']) && filled($params['box_id'])) {
            $query->where('box_id', '=', $params['box_id']);
        }

        // 产品id
        if (isset($params['product_id']) && filled($params['product_id'])) {
            $query->where('product_id', '=', $params['product_id']);
        }

        // 产品图片
        if (isset($params['img_url']) && filled($params['img_url'])) {
            $query->where('img_url', 'like', '%' . $params['img_url'] . '%');
        }

        // 产品价格
        if (isset($params['price']) && filled($params['price'])) {
            $query->where('price', '=', $params['price']);
        }

        // 概率-展示给前台用的
        if (isset($params['probability']) && filled($params['probability'])) {
            $query->where('probability', '=', $params['probability']);
        }

        // 权重-后台计算用的
        if (isset($params['weight']) && filled($params['weight'])) {
            $query->where('weight', '=', $params['weight']);
        }

        // 展示状态(1正常,2禁用)
        if (isset($params['status']) && filled($params['status'])) {
            $query->where('status', '=', $params['status']);
        }

        // 创建者
        if (isset($params['created_by']) && filled($params['created_by'])) {
            $query->where('created_by', '=', $params['created_by']);
        }

        // 创建时间
        if (isset($params['create_time']) && filled($params['create_time'])) {
            $query->where('create_time', '=', $params['create_time']);
        }

        // 更新时间
        if (isset($params['update_time']) && filled($params['update_time'])) {
            $query->where('update_time', '=', $params['update_time']);
        }

        return $query;
    }


    /**
     * 新增数据.
     */
    public function saveData(array $data)
    {
        $modeType = \App\Box\Model\BoxInfo::query()->where('id', $data['box_id'])->value('mode_type');
        switch ($modeType) {
            case \App\Box\Model\BoxInfo::MODE_TYPE_PRICE : //变价箱子
                $data = $this->savePriceProduct($data);
                break;
            case \App\Box\Model\BoxInfo::MODE_TYPE_GOODS : //变物箱子
                $data = $this->saveGoodsProduct($data);
                break;
            case \App\Box\Model\BoxInfo::MODE_TYPE_ACTIVITY : //活动箱子
                $data = $this->saveActivityProduct($data);
                break;
        }
        $this->filterExecuteAttributes($data, $this->getModel()->incrementing);
        $model = $this->model::create($data);
        $res = $model->{$model->getKeyName()};
        switch ($modeType) {
            case \App\Box\Model\BoxInfo::MODE_TYPE_PRICE : //变价箱子
                $data = $this->changeBoxPriceUpdate($data['box_id']);
                break;
            case \App\Box\Model\BoxInfo::MODE_TYPE_GOODS : //变物箱子
                $data = $this->changeBoxGoodsUpdate($data['box_id']);
                break;
            case \App\Box\Model\BoxInfo::MODE_TYPE_ACTIVITY : //活动箱子
                $data = $this->changeBoxPriceUpdate($data['box_id']);
                break;
        }
        return $res;
    }

    public function updateData($id, $data)
    {
        $modeType = \App\Box\Model\BoxInfo::query()->where('id', $data['box_id'])->value('mode_type');
        switch ($modeType) {
            case \App\Box\Model\BoxInfo::MODE_TYPE_PRICE : //变价箱子
                $data = $this->savePriceProduct($data);
                break;
            case \App\Box\Model\BoxInfo::MODE_TYPE_GOODS : //变物箱子
                $data = $this->saveGoodsProduct($data);
                break;
            case \App\Box\Model\BoxInfo::MODE_TYPE_ACTIVITY : //活动箱子
                $data = $this->saveActivityProduct($data);
                break;
        }
        $this->filterExecuteAttributes($data, true);
        $res = $this->model::find($id)->update($data) > 0;


        //变价与变物
        switch ($modeType) {
            case \App\Box\Model\BoxInfo::MODE_TYPE_PRICE : //变价箱子
                $data = $this->changeBoxPriceUpdate($data['box_id']);
                break;
            case \App\Box\Model\BoxInfo::MODE_TYPE_GOODS : //变物箱子
                $data = $this->changeBoxGoodsUpdate($data['box_id']);
                break;
            case \App\Box\Model\BoxInfo::MODE_TYPE_ACTIVITY : //活动箱子
                $data = $this->changeBoxPriceUpdate($data['box_id']);
                break;
        }
        return $res;
    }


    /**
     * 变价新组成数组
     * @param $data
     * @return mixed
     * @throws \ErrorException\
     */
    public function savePriceProduct($data)
    {
        if (empty($data['product_id'])) {
            throw new \ErrorException('请选择产品');
        }
        $data['product_id'] = is_array($data['product_id']) ? $data['product_id'][0] : $data['product_id'];
        $produtInfo = \App\Config\Model\ConfigProduct::query()->where('id', $data['product_id'])->first();
        $data['product_name'] = $produtInfo['name'];
        $data['img_url'] = $produtInfo['cover'];
        $data['price'] = $produtInfo['price'];
        $data['weight'] = ($data['price'] * \App\Lib\AdminEnum::PRICE_MULTIPLE);
        if ($data['status'] != AdminEnum::STATUS_YES) {  //被禁用概率清零
            $data['probability'] = 0;
        }
        return $data;
    }

    /**
     * 变物新组成数组
     * @param $data
     * @return mixed
     * @throws \ErrorException\
     */
    public function saveGoodsProduct($data)
    {
        $produtInfo = \App\Config\Model\ConfigProduct::getProductByNearPrice($data['max_price'] * AdminEnum::PRICE_MULTIPLE);
        if (empty($produtInfo)) {
            throw new ErrorException('抱歉,查无产品');
        }
        $data['product_id'] = $produtInfo['id'];
        $data['product_name'] = $produtInfo['name'];
        $data['img_url'] = $produtInfo['cover'];
        $data['price'] = $produtInfo['price'];
        $data['max_price'] = $data['max_price'];
        $data['weight'] = $data['price'] * \App\Lib\AdminEnum::PRICE_MULTIPLE;
        if ($data['status'] != AdminEnum::STATUS_YES) {  //被禁用概率清零
            $data['probability'] = 0;
        }
        return $data;
    }

    public function saveActivityProduct($data)
    {
        $data['product_id'] = $data['product_id'][0];
        $produtInfo = \App\Config\Model\ConfigProduct::query()->where('id', $data['product_id'])->first();
        $data['product_name'] = $produtInfo['name'];
        $data['img_url'] = $produtInfo['cover'];
        $data['price'] = $produtInfo['price'] * AdminEnum::PRICE_MULTIPLE;
    }


    /**
     * 变价
     * @param $boxId 箱子id
     * @param $upPriceFlag  是否更新箱子售价  1更新2不更新
     * @return void
     */
    public function changeBoxPriceUpdate($boxId, $upPriceFlag = self::UPDATE_BOX_PRICE_YES)
    {
        $priceCoefficientArr = [];//计算售价的数组，产品需求用户原价(这里用售价)
        if (!empty($boxId)) {
            $productPriceArr = $this->model::query()
                ->leftJoin('config_product', 'box_product.product_id', '=', 'config_product.id')
                ->where('box_product.box_id', $boxId)
                ->where('box_product.status', AdminEnum::STATUS_YES)
                ->pluck('config_product.price', 'box_product.id');

            $sumWeight = 0; //总价格
            foreach ($productPriceArr as $id => $price) {
                $sumWeight = $sumWeight + $price;
                $updateData[$id]['price'] = $price;  //更新价格
                $priceCoefficientArr[$id]['price'] = $price;
            }
            $newSumWeight = 0;  //新的总概率（注意：$productPriceArr已被复值为新的权重值）
            foreach ($productPriceArr as $id => $price) {
                $productPriceArr[$id] = number_format($sumWeight / $price, 2, '.', '') * 100;  //售价权重：总价格/商品价(越小价格，权重就越高)
                $updateData[$id]['weight'] = $productPriceArr[$id];  //更新权重
                $newSumWeight = $newSumWeight + $productPriceArr[$id];
            }
            $sumProbability = 0;
            $maxId = 0; //最大id;
            $maxPrice = 0; //最大值
            foreach ($productPriceArr as $id => $price) {
                $updateData[$id]['probability'] = number_format($price / $newSumWeight, 5, '.', '') * AdminEnum::BOX_PROBABILITY_SUM; //放大概率10000
                $sumProbability = $sumProbability + $updateData[$id]['probability'];
                if (($price) > $maxPrice) {
                    $maxPrice = $price;
                    $maxId = $id;
                }
                $priceCoefficientArr[$id]['probability'] = $updateData[$id]['probability'];
            }
            echo '-------------->>>' . PHP_EOL;
            $diffProbability = AdminEnum::BOX_PROBABILITY_SUM - $sumProbability; //相差概率 (意思概率累加起来为1,为什么要减10000，因为总概率被放大10000)
            $updateData[$maxId]['probability'] = $updateData[$maxId]['probability'] + $diffProbability; //相加为1;
            $priceCoefficientArr[$maxId]['probability'] = $updateData[$maxId]['probability'];
            $updateData[$maxId]['weight'] = $updateData[$maxId]['probability'];  //更新权重
            $updateSql = 'update us_box_product set update_time=\'' . time() . '\', price = case id ';;//批量更新
            foreach ($updateData as $id => $itemPrice) {
                $updateSql = $updateSql . ' when ' . $id . ' then ' . $itemPrice['price'] . ' ';
            }
            $updateSql = $updateSql . " END,weight = case id ";
            foreach ($updateData as $id => $itemPrice) {
                $updateSql = $updateSql . ' when ' . $id . ' then ' . $itemPrice['weight'] . ' ';
            }
            $updateSql = $updateSql . " END,probability = case id ";
            $productUpdateIds = [];
            foreach ($updateData as $id => $itemPrice) {
                $updateSql = $updateSql . ' when ' . $id . ' then ' . $itemPrice['probability'] . ' ';
                $productUpdateIds[] = $id;
            }
            //---
            if (!empty($productUpdateIds)) {
                $updateSql = $updateSql . 'END WHERE id IN (' . implode(',', $productUpdateIds) . ')';
                Db::select($updateSql);
            }
        }
        //----------根据售价系统更新售价---------------
        $this->upBoxPrice($priceCoefficientArr, $boxId, $upPriceFlag); //更新箱子售价
        return [];
    }

    /**
     * 变物
     * @param $boxId
     * @return void
     */
    public function changeBoxGoodsUpdate($boxId, $upPriceFlag = self::UPDATE_BOX_PRICE_YES)
    {
        echo '-----开始:变物------->>' . PHP_EOL;
        if (!empty($boxId)) {
            //先更新物品--获取产品最高价
            $productMaxPriceArr = $this->model::query()
                ->where('box_id', $boxId)
                ->where('status', $this->model::STATUS_YES)
                ->pluck('max_price', 'id');
            foreach ($productMaxPriceArr as $key => $val) {
                $produtInfo = \App\Config\Model\ConfigProduct::getProductByNearPrice($val * AdminEnum::PRICE_MULTIPLE);
                if (empty($produtInfo)) {
                    throw new ErrorException('抱歉,查无产品');
                }
                $data = [];
                $data['product_id'] = $produtInfo['id'];
                $data['product_name'] = $produtInfo['name'];
                $data['img_url'] = $produtInfo['cover'];
                $data['price'] = $produtInfo['price'];
                $data['weight'] = $data['price'] * AdminEnum::PRICE_MULTIPLE;
                $this->model::find($key)->update($data);
            }
            $this->changeBoxPriceUpdate($boxId, $upPriceFlag);
        }
    }

    /**
     * 更新商品售价
     * @param $priceCoefficientArr
     * @param $boxId
     * @param $upPriceFlag
     * @return array|void
     */
    public function upBoxPrice($priceCoefficientArr, $boxId, $upPriceFlag = 1)
    {
        if ($upPriceFlag != self::UPDATE_BOX_PRICE_YES) { //如果1则更新,不为1则不更新
            return [];
        }
        $priceCoefficient = \App\Box\Model\BoxInfo::query()
            ->where('id', $boxId)
            ->value('price_coefficient');
        $averageSumPrice = 0;//平均期望返值
        foreach ($priceCoefficientArr as $v) {
            $averageSumPrice = $averageSumPrice + number_format(($v['price'] / AdminEnum::PRICE_MULTIPLE) * ($v['probability'] / AdminEnum::BOX_PROBABILITY_SUM), 4, '.', '');
        }
        if (!empty($priceCoefficient) && $priceCoefficient != '0.00') {  //如果箱子售价系数为0则不更新售价
            $boxPrice = number_format($averageSumPrice / $priceCoefficient, 2, '.', '') * AdminEnum::PRICE_MULTIPLE;
            \App\Box\Model\BoxInfo::query()->where('id', $boxId)->update(['price' => $boxPrice]);
        }
    }
}